package com.auxgroup.smarthome.inner.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auxgroup.bridge.app.inner.dto.DeviceInfoWithTokenDto;
import com.auxgroup.bridge.app.inner.vo.AppDeviceInfoListVo;
import com.auxgroup.bridge.app.inner.vo.DeviceFaultVo;
import com.auxgroup.bridge.app.inner.vo.DeviceInfoNewVo;
import com.auxgroup.bridge.app.inner.vo.DeviceInfoVo;
import com.auxgroup.bridge.business.inner.vo.DeviceExportDataVo;
import com.auxgroup.bridge.business.inner.vo.DeviceListVo;
import com.auxgroup.bridge.business.inner.vo.UserDeviceListVo;
import com.auxgroup.smarthome.BeanUtils;
import com.auxgroup.smarthome.appconst.AppConstant;
import com.auxgroup.smarthome.constant.cache.CachedConsant;
import com.auxgroup.smarthome.enterprise.service.DeviceManageService;
import com.auxgroup.smarthome.enterpriseapi.requestbody.BindAndUnbindBody;
import com.auxgroup.smarthome.enterpriseapi.responsebody.DeviceMessage;
import com.auxgroup.smarthome.inner.entity.DeviceInfoEntity;
import com.auxgroup.smarthome.inner.entity.DeviceModelInfoEntity;
import com.auxgroup.smarthome.inner.entity.UserDeviceEntity;
import com.auxgroup.smarthome.inner.repo.DeviceInfoEntityRepo;
import com.auxgroup.smarthome.inner.repo.DeviceModelInfoRepo;
import com.auxgroup.smarthome.inner.repo.UserDeviceEntityRepo;
import com.auxgroup.smarthome.inner.util.DeviceHelper;
import com.auxgroup.smarthome.openapi.OpenApi;
import com.auxgroup.smarthome.openapi.requestbody.BindDidDeviceInfo;
import com.auxgroup.smarthome.openapi.requestbody.UnBindDidDeviceInfo;
import com.auxgroup.smarthome.openapi.responsebody.BindAndUnbindStatus;
import com.auxgroup.smarthome.redis.config.ObjectRedis;
import com.auxgroup.smarthome.syscode.AppCode;
import com.auxgroup.smarthome.syscode.BusinessCode;
import com.auxgroup.smarthome.syscode.Syscode;
import com.auxgroup.smarthome.utils.common.LOG;
import com.auxgroup.smarthome.web.ApiResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

/**
 * Created by fju on 2017/7/25.
 */
@Service
public class DeviceInfoDBService {

    // 开机时间阈值30000分钟
    private final int BOOT_TIME_THRESHOLD = 30000;
    @Autowired
    private DeviceInfoEntityRepo deviceInfoEntityRepo;
    @Autowired
    private UserDeviceEntityRepo userDeviceEntityRepo;
    @Autowired
    private ObjectRedis objectRedis;
    @Autowired
    private DeviceModelInfoRepo deviceModelInfoRepo;
    @Autowired
    private DeviceManageService deviceManageService;

    /**
     * 查找设备分页,只显示非古北云设备
     *
     * @param deviceStatus
     * @param keywords
     * @param pageable
     * @return
     */
    public Page<DeviceListVo> findDevicePage(String modelId, String deviceStatus, String keywords, Pageable pageable) {
        Pair<String, ArrayList> queryPair = getDeviceListSql(modelId, deviceStatus, keywords);
        Page<DeviceListVo> resultList = deviceInfoEntityRepo.findBySql(queryPair.getLeft(), queryPair.getRight(), pageable, DeviceListVo.class);
        return resultList;
    }

    /**
     * 查找设备列表
     *
     * @param modelId
     * @param deviceStatus
     * @param keywords
     * @param pageable
     * @return
     */
    public List<DeviceListVo> findDeviceList(String modelId, String deviceStatus, String keywords, Pageable pageable) {
        Pair<String, ArrayList> queryPair = getDeviceListSql(modelId, deviceStatus, keywords);
        List<DeviceListVo> resultList = deviceInfoEntityRepo.findBySql(queryPair.getLeft(), queryPair.getRight(), DeviceListVo.class);
        return resultList;
    }

    private Pair<String, ArrayList> getDeviceListSql(String modelId, String deviceStatus, String keywords) {
        StringBuilder querySql = new StringBuilder("select distinct di.device_id , di.product_key , di.mac, di.did, di.sn, di.is_online as online , di.source, di.created_at, di.latest_online_time from device_info di WHERE di.is_trash = 0 and source <> 0 ");
        ArrayList<Object> param = new ArrayList<>();
        if (StringUtils.isNoneBlank(deviceStatus)) {
            querySql.append(" and ").append("di.is_online=? ");
            param.add(Integer.valueOf(deviceStatus));
        }
        if (StringUtils.isNoneBlank(keywords)) {
            querySql.append(" and ").append("(di.mac like ? or di.did like ? or di.sn like ?) ");
            param.add("%" + keywords + "%");
            param.add("%" + keywords + "%");
            param.add("%" + keywords + "%");
        }
        if (StringUtils.isNoneBlank(modelId)) {
            querySql.append(" and ").append(" di.model_id=? ");
            param.add(modelId);
        }
        querySql.append(" order by di.is_online desc");
        return Pair.of(querySql.toString(), param);
    }

    /**
     * 获取导出数据
     *
     * @param modelId
     * @param deviceStatus
     * @param keywords
     * @return
     */
    public List<DeviceExportDataVo> getDeviceExportData(String modelId, String deviceStatus, String keywords) {
        StringBuilder querySql = new StringBuilder("select distinct di.device_id , di.product_key , di.mac, di.did, di.sn, di.is_online as online , di.source, di.created_at, di.latest_online_time, IF(TRUNCATE(IF(aff.boot_time IS NULL, 0, aff.boot_time)/").append(BOOT_TIME_THRESHOLD).append(",2)*100>100, 0, 100-TRUNCATE(IF(aff.boot_time IS NULL, 0, aff.boot_time)/").append(BOOT_TIME_THRESHOLD).append(",2)*100) as mesh_life FROM ");
        querySql.append(" device_info di ")
                .append(" LEFT JOIN app_filter_fault aff ON aff.mac = di.mac ")
                .append(" WHERE di.is_trash = 0 and source <> 0 ");
        ArrayList<Object> param = new ArrayList<>();
        if (StringUtils.isNoneBlank(deviceStatus)) {
            querySql.append(" and ").append("di.is_online=? ");
            param.add(Integer.valueOf(deviceStatus));
        }
        if (StringUtils.isNoneBlank(keywords)) {
            querySql.append(" and ").append("(di.mac like ? or di.did like ? or di.sn like ?) ");
            param.add("%" + keywords + "%");
            param.add("%" + keywords + "%");
            param.add("%" + keywords + "%");
        }
        if (StringUtils.isNoneBlank(modelId)) {
            querySql.append(" and ").append(" di.model_id=? ");
            param.add(modelId);
        }
        List<DeviceExportDataVo> resultList = deviceInfoEntityRepo.findBySql(querySql.toString(), param, DeviceExportDataVo.class);
        return resultList;
    }


    /**
     * 查找设备详情
     *
     * @param deviceId
     * @return
     */
    public ApiResponse<DeviceListVo> findByDeviceId(String deviceId) {
        DeviceInfoEntity deviceInfoEntity = deviceInfoEntityRepo.findByDeviceIdAndTrashFalse(deviceId);
        if (null != deviceInfoEntity) {
            DeviceListVo deviceListVo = new DeviceListVo(deviceInfoEntity.getDeviceId(), deviceInfoEntity.getProductKey(), deviceInfoEntity.getMac(), deviceInfoEntity.getDid(), deviceInfoEntity.getSn(), deviceInfoEntity.getOnline(), deviceInfoEntity.getCreatedAt());
            return ApiResponse.ok(deviceListVo);
        }
        return ApiResponse.ok(null);
    }

    /**
     * ***重要***
     * 哥，千万别动，和pass同步型号相关数据，首页统计数据相关
     * 出现问题看着办吧
     *
     * @param modelId
     * @param sn
     * @param userType
     * @return
     */
    private String synchronizeRemarkDataWithPass(String modelId, String sn, int userType) {
        if (null == sn) sn = "";
        JSONObject remark = new JSONObject();
        remark.put("deviceModel", modelId);
        remark.put("deviceSn", sn);
        remark.put("isHang", userType);
        return remark.toJSONString();
    }

    /**
     * 配网流程-绑定设备
     *
     * @param deviceInfoWithTokenDto
     * @return
     */
    @Transactional(readOnly = false)
    public ApiResponse<DeviceInfoNewVo> bindDevice(DeviceInfoWithTokenDto deviceInfoWithTokenDto) {
        DeviceModelInfoEntity deviceModelInfoEntity = deviceModelInfoRepo.findByModelIdAndTrashFalse(deviceInfoWithTokenDto.getModelId());
        if (deviceModelInfoEntity == null) {
            LOG.error(this, "没有相关的型号");
            return ApiResponse.prompt(AppCode.MODEL_NOT_EXISTS);
        }
        // 选择的设备型号的设备类型与实际的设备类型不一致
        if (!deviceModelInfoEntity.getDeviceType().equals(deviceInfoWithTokenDto.getSource())) {
            return ApiResponse.prompt(AppCode.MODEL_DEVICE_NOT_MATCH);
        }
        String remark = synchronizeRemarkDataWithPass(deviceModelInfoEntity.getModelId(), deviceInfoWithTokenDto.getSn(), deviceModelInfoEntity.getUseType());
        deviceInfoWithTokenDto.setRemark(remark);
        String appid = deviceInfoWithTokenDto.getAppId();
        /**----------begin modify by lixiaoxiao 20180315
         * 场景1.当新设备配置为旧设备时,如果paas绑定返回成功,则强制修改设备属性为新设备;
         * 场景2.当新设备配置为新设备时,如果paas绑定返回成功,则保存数据在saas;如果paas绑定返回失败,则直接返回;
         * 场景3.当旧设备配置为新设备时,paas绑定返回失败,保存旧设备数据在saas;
         * 场景4.当旧设备配置为旧设备时,同3;
         */
        //1.拿设备去paas做绑定
        String newMac = deviceInfoWithTokenDto.getMac().replaceAll(":","").toUpperCase();;
        String oldMac = transNewToOld(newMac);
        //删除设备数据并解除绑定
        clearDevice(appid,newMac,oldMac);
        int source = deviceInfoWithTokenDto.getSource();
        ApiResponse apiResponse = getNewOrOldFromPaas(deviceInfoWithTokenDto,newMac);
        DeviceInfoEntity deviceInfoEntity = new DeviceInfoEntity();
        if(apiResponse.getCode() == AppCode.SC_OK.getCode()){
            //成功为新设备
            DeviceInfoWithTokenDto returnDto = ((DeviceInfoWithTokenDto)apiResponse.getData());
            deviceInfoWithTokenDto.setMac(newMac);
            BeanUtils.copyAttrs(deviceInfoEntity,deviceInfoWithTokenDto);
            deviceInfoEntity.setSource(1);
            deviceInfoEntity.bindDidAndPasscode(returnDto.getDid(),returnDto.getPassword());
        }else{
            //失败如果选择新型号直接返回
            if (source == 1) {
                return apiResponse;
            }
            BeanUtils.copyAttrs(deviceInfoEntity,deviceInfoWithTokenDto);
        }
        if (StringUtils.isEmpty(deviceInfoEntity.getAlias())) {
            deviceInfoWithTokenDto.setAlias("奥克斯空调");
            deviceInfoEntity.setAlias("奥克斯空调");
        }
        //----------end modify by lixiaoxiao 20180315
        if (StringUtils.isEmpty(deviceInfoWithTokenDto.getSn())) {
            deviceInfoEntity.setSn(null);
        }
        deviceInfoEntity.setRemark(remark);
        deviceInfoEntity.setOnline(true);
        deviceInfoEntity = deviceInfoEntityRepo.save(deviceInfoEntity);
        //绑定用户和设备的关系
        UserDeviceEntity userDeviceEntity = new UserDeviceEntity();
        userDeviceEntity.bindUserAndDevice(deviceInfoEntity.getDeviceId(), deviceInfoWithTokenDto);
        userDeviceEntityRepo.save(userDeviceEntity);

        // 重新配网，把所有设备分享缓存清理掉
        clearDeviceShareRedis(deviceInfoEntity.getDeviceId(), null);

        DeviceInfoNewVo deviceInfoNewVo = deviceInfoEntity.createDeviceInfoNewVo();
        return ApiResponse.ok(deviceInfoNewVo);
    }

    /**
     * 保存数据到Paas
     *
     * @param deviceInfoWithTokenDto
     * @return 是否保存成功
     */
    private ApiResponse saveToPaas(DeviceInfoWithTokenDto deviceInfoWithTokenDto) {
        String appid = deviceInfoWithTokenDto.getAppId();
        String token = deviceInfoWithTokenDto.getToken();

        BindDidDeviceInfo bindDidDeviceInfo = new BindDidDeviceInfo(
                deviceInfoWithTokenDto.getDid(),         //did
                deviceInfoWithTokenDto.getPassword(),    //passcode
                deviceInfoWithTokenDto.getRemark(),                   //remark
                deviceInfoWithTokenDto.getAlias(),       //alias
                ""                                       //mdid
        );
        LOG.info(this, "配网-》调用Openapi==>参数" + JSONObject.toJSONString(bindDidDeviceInfo));
        BindAndUnbindStatus bindDidRes = OpenApi.bindDid(appid, token, bindDidDeviceInfo);
        LOG.info(this, "配网-》调用Openapi==>结果" + JSONObject.toJSONString(bindDidRes));
        // 云端绑定失败，返回详细错误信息
        if (StringUtils.isNotEmpty(bindDidRes.getError_code())) {
            LOG.error(bindDidRes, bindDidRes.getError_message());
            return ApiResponse.prompt(bindDidRes.getError_code(), bindDidRes.getError_message());
        }
        if (bindDidRes.judgeFailed(deviceInfoWithTokenDto.getDid())) {
            return ApiResponse.prompt(AppCode.GIZWITS_DEVICE_BIND_FAIL.getCode() + "", "绑定失败did:" + JSON.toJSONString(bindDidRes.getFailed()));
        }
        return ApiResponse.prompt(AppCode.SC_OK);
    }

    /**
     * 清除设备缓存
     *
     * @param deviceId
     * @param uid
     */
    private void clearDeviceShareRedis(String deviceId, String uid) {
        StringBuilder key = new StringBuilder();
        key.append(CachedConsant.DEVICE_SHARE_CACHED_PREFIX).append(deviceId).append("/");
        if (StringUtils.isBlank(uid)) {
            key.append("*");
        } else {
            key.append(uid);
        }
        objectRedis.deleteByPattern(key.toString());
    }

    /**
     * 健康键8下进入配网模式，清除设备所有绑定关系
     *
     * @param deviceInfoEntity
     * @return
     */
    private ApiResponse clearDeviceRelation(String appid, DeviceInfoEntity deviceInfoEntity) {
        if (null != deviceInfoEntity) {
            int source = deviceInfoEntity.getSource();
            List<UserDeviceEntity> userDeviceEntitys = userDeviceEntityRepo.findByDeviceIdAndTrashFalse(deviceInfoEntity.getDeviceId());
            // 机智云设备需要先从云端解绑
            if (source == 1) {
                ApiResponse gizwitsUnbind = relieveGizwitsDeviceBind(appid, deviceInfoEntity.getProductKey(), userDeviceEntitys);
                if (gizwitsUnbind.getCode() != AppCode.SC_OK.getCode()) {
                    return gizwitsUnbind;
                }
            } else if (source == 0) { // 古北云解除绑定操作逻辑
                if (userDeviceEntitys.size() > 0) {
                    int row = userDeviceEntityRepo.deleteRelationship(deviceInfoEntity.getDeviceId());
                    LOG.info(this, "设备解除绑定操作:" + row + "条记录");
                }
            }

        }
        return ApiResponse.prompt(AppCode.SC_OK);
    }

    /**
     * 基础机智云设备用户绑定
     *
     * @param appid
     * @param productKey
     * @param userDeviceEntitys
     * @return
     */
    private ApiResponse relieveGizwitsDeviceBind(String appid, String productKey, List<UserDeviceEntity> userDeviceEntitys) {
        List<String> failedDid = new ArrayList<>();
        userDeviceEntitys.stream().forEach(userDeviceEntity -> {

            BindAndUnbindBody bindAndUnbindBody = new BindAndUnbindBody(userDeviceEntity.getUid(), appid, new String[]{userDeviceEntity.getDid()});
            LOG.info(this, "主动解绑-》调用Enterpriseapi==>参数" + JSONObject.toJSONString(bindAndUnbindBody));
            ApiResponse<com.auxgroup.smarthome.enterpriseapi.responsebody.BindAndUnbindStatus> unbindResult = deviceManageService.unbindDevices(productKey, bindAndUnbindBody);
            LOG.info(this, "主动解绑-》调用Enterpriseapi==>结果" + JSONObject.toJSONString(unbindResult));
            // 解绑异常返回机智云错误提示
            if (!unbindResult.isNotErrorCode()) {
                failedDid.add(userDeviceEntity.getDid());
            } /*else {*/
            // 云端解绑成功，SASS同步解绑
            userDeviceEntity.setTrash(true);
            userDeviceEntityRepo.save(userDeviceEntity);
                /*}*/

        });
        if (failedDid.size() > 0) {
            return ApiResponse.prompt(AppCode.GIZWITS_DEVICE_UNBIND_FAIL.getCode() + "", "解绑失败did:" + Arrays.toString(failedDid.toArray()));
        }
        return ApiResponse.prompt(AppCode.SC_OK);
    }

    /**
     * 获取用户设备
     *
     * @param uid
     * @param pageable
     * @return
     */
    public Page<UserDeviceListVo> getUserDeviceList(String uid, Pageable pageable) {
        String querySql = "select DISTINCT di.*, ud.user_tag from user_device ud left join device_info di ON  (ud.device_id = di.device_id AND  di.is_trash = 0) where ud.is_trash = 0 and ud.uid = ?";
        Page<UserDeviceListVo> page = deviceInfoEntityRepo.findBySql(querySql, Arrays.asList(uid), pageable, UserDeviceListVo.class);

        return page;
    }

    /**
     * 解绑设备
     *
     * @param userId
     * @param appId
     * @param deviceId
     * @return
     */
    @Transactional(readOnly = false)
    public ApiResponse unBindDevice(String userId, String appId, String token, String deviceId) {
        //检查用户是否存在绑定关系
        UserDeviceEntity userDeviceEntity = userDeviceEntityRepo.findByUidAndDeviceIdAndTrashFalse(userId, deviceId);
        if (userDeviceEntity == null) {
            return ApiResponse.prompt(AppCode.USER_RELATION_DEVICE_NOT_EXIST);
        }
        //读取设备
        DeviceInfoEntity deviceInfoEntity = deviceInfoEntityRepo.findOne(deviceId);
        if (deviceInfoEntity == null) {
            return ApiResponse.prompt(AppCode.DEVICE_NOT_EXIST);
        }
        // 设备来源，0古北云设备，1机智云设备
        int source = deviceInfoEntity.getSource();
        // 用户标签：0：主人，1：家人，2：朋友
        int userTag = userDeviceEntity.getUserTag();

        if (userTag == 0) { // 主人解除绑定，包括主人分享的设备全部解除分享
            List<UserDeviceEntity> userDeviceEntitys = userDeviceEntityRepo.findByDeviceIdAndTrashFalse(deviceId);
            if (source == 1) {// 机智云设备解除绑定
                ApiResponse gizwitsUnbind = relieveGizwitsDeviceBind(appId, deviceInfoEntity.getProductKey(), userDeviceEntitys);
                // TODO 别删除，平台解绑失败，暂不处理，SASS也会解绑
//                if(gizwitsUnbind.getCode() != AppCode.SC_OK.getCode()) {
//                    return gizwitsUnbind;
//                }
                deviceInfoEntity.setSn(null);
                deviceInfoEntityRepo.save(deviceInfoEntity);

            } else if (source == 0) {
                if (unBindAtSaas(userDeviceEntity.getDeviceId())) {
                    deviceInfoEntity.setSn(null);
                    deviceInfoEntityRepo.save(deviceInfoEntity);
                }
            }
            // 主人解绑，删除该设备的所有分享缓存
            clearDeviceShareRedis(deviceInfoEntity.getDeviceId(), null);
            return ApiResponse.prompt(AppCode.SC_OK);
            // 家人
        } else if (userTag == 1) {
            // 家人解绑先解绑子用户和设备关系
            LOG.info(this, "家人解绑设备数据,mac:" + userDeviceEntity.getMac() + "--uid:" + userDeviceEntity.getUid());
            DeviceHelper.unbindSubuserDevice(userDeviceEntityRepo, deviceInfoEntityRepo, objectRedis, deviceManageService, appId, userDeviceEntity);
            userDeviceEntity.setTrash(true);
            userDeviceEntityRepo.save(userDeviceEntity);
            // 好友
        } else if (userTag == 2) {
            if (source == 1) { // 机智云单个设备解绑
                List<HashMap<String, String>> devices = new ArrayList<>();
                HashMap<String, String> device = new HashMap<>();
                device.put("did", deviceInfoEntity.getDid());
                devices.add(device);
                UnBindDidDeviceInfo unBindDidDeviceInfo = new UnBindDidDeviceInfo(devices);
                LOG.info(this, "调用Openapi开始===>参数：" + JSONObject.toJSONString(unBindDidDeviceInfo));
                BindAndUnbindStatus unBindDidRes = OpenApi.unbindDid(appId, token, unBindDidDeviceInfo);
                LOG.info(this, "调用Openapi结束==》结果" + JSONObject.toJSONString(unBindDidRes));
                if (StringUtils.isNotEmpty(unBindDidRes.getError_code())) {
                    return ApiResponse.prompt(unBindDidRes.getError_code(), unBindDidRes.getError_message());
                }
                if (unBindDidRes.judgeFailed(deviceInfoEntity.getDid())) {
                    return ApiResponse.prompt(AppCode.GIZWITS_DEVICE_UNBIND_FAIL.getCode() + "", "解绑失败did:" + deviceInfoEntity.getDid());
                }
            }
            userDeviceEntity.setTrash(true);
            userDeviceEntityRepo.save(userDeviceEntity);
            // 好友解绑，删除该用户的分享缓存
            clearDeviceShareRedis(deviceInfoEntity.getDeviceId(), userDeviceEntity.getUid());
        }
        return ApiResponse.prompt(AppCode.SC_OK);
    }

    /**
     * 在Saas解除绑定
     *
     * @param deviceId
     * @return
     */
    private Boolean unBindAtSaas(String deviceId) {
        int row = userDeviceEntityRepo.deleteRelationship(deviceId);
        LOG.info(this, "设备绑定操作-解除关系链[主人,分享]:" + row);
        return row > 0;
    }

    /**
     * 获取app端设备列表
     *
     * @param uid
     * @return
     */
    public List<AppDeviceInfoListVo> getAppDeviceList(String uid) {
        StringBuilder querySql = new StringBuilder();
        querySql.append(" SELECT device.*, ud.uid, ud.user_tag, dmi.suit_type, dmi.device_main_uri, dmi.entity_uri, dmi.use_type, dmi.feature, aff.is_wash FROM device_info device ")
                .append("LEFT JOIN user_device ud ON (device.device_id = ud.device_id AND ud.is_trash = 0) ")
                .append("LEFT JOIN device_model_info dmi ON (dmi.model_id = device.model_id AND dmi.is_trash = 0) ")
                .append("LEFT JOIN app_filter_fault aff ON device.mac = aff.mac ")
                .append("WHERE device.is_trash = 0 AND (device.source =0 OR device.source =1 ) AND ud.uid = ? ORDER BY device.created_at DESC ");

        List<AppDeviceInfoListVo> resultList = deviceInfoEntityRepo.findBySql(querySql.toString(), Arrays.asList(uid), AppDeviceInfoListVo.class);
        return resultList;
    }

    /**
     * 根据 did 来获取实物图Uri
     * 支持缓存，缓存时长[60 * 12]分钟
     *
     * @param did
     * @return 实物图Uri
     */
    private String getEntityUri(String did) {
        //缓存路径 /device/{did}/entity_url/
        String cachePath = "/device/" + did + "/entity_url";
        String entityUri = objectRedis.get(cachePath, String.class);
        if (entityUri == null) {
            entityUri = deviceInfoEntityRepo.findEntityUri(did);
            if (entityUri == null) {
                entityUri = "";
            } else {
                objectRedis.add(cachePath, 12 * 60L, entityUri);
            }
        }
        return entityUri;
    }

    /**
     * 检查设备Id是否合法
     *
     * @param deviceId
     * @return
     */
    public ApiResponse<Boolean> exist(String deviceId) {
        return ApiResponse.ok(deviceInfoEntityRepo.findByDeviceIdAndTrashFalse(deviceId) != null);
    }

    /**
     * 获取did对应的deviceId
     *
     * @param did
     * @return deviceId 或者 ""
     */
    public ApiResponse<String> getMappedDeviceId(String did) {
        DeviceInfoEntity deviceInfoEntity = deviceInfoEntityRepo.findByDidAndTrashFalse(did);
        if (deviceInfoEntity == null) {
            return ApiResponse.ok("");
        }
        return ApiResponse.ok(deviceInfoEntity.getDeviceId());
    }

    /**
     * 获取deviceId对应的did
     *
     * @param deviceId
     * @return did 或者 ""
     */
    public ApiResponse<String> getMappedDid(String deviceId) {
        DeviceInfoEntity deviceInfoEntity = deviceInfoEntityRepo.findByDeviceIdAndTrashFalse(deviceId);
        if (deviceInfoEntity == null) {
            return ApiResponse.ok("");
        }
        return ApiResponse.ok(deviceInfoEntity.getDid());
    }

    /**
     * 获取与设备型号的新旧 0:老设备古北云 1:新设备机智云
     *
     * @param deviceId
     * @return
     */
    public ApiResponse<Integer> getDeviceManufacturers(String deviceId) {
        DeviceInfoEntity deviceInfo = deviceInfoEntityRepo.findByDeviceIdAndTrashFalse(deviceId);

        return ApiResponse.ok(deviceInfo.getSource());
    }

    /**
     * 根据设备id获取设备信息
     * add by lixiaoxiao 2017-9-4
     *
     * @param deviceId
     * @return
     */
    public ApiResponse<DeviceInfoVo> getDeviceInfo(String deviceId) {
        DeviceInfoEntity deviceInfo = deviceInfoEntityRepo.findByDeviceIdAndTrashFalse(deviceId);
        return ApiResponse.ok(BeanUtils.copyAttrs(new DeviceInfoVo(), deviceInfo));
    }

    /**
     * 修改设备部分信息
     *
     * @param sn
     * @param alias
     * @return
     */
    @Transactional
    public ApiResponse updateDeviceInfo(String uid, String mac, String sn, String alias) {
        String newMac = mac.replaceAll(":", "").toUpperCase();
        DeviceInfoEntity deviceInfoEntity = deviceInfoEntityRepo.findByMacAndTrashFalse(newMac);
        if (deviceInfoEntity == null) {
            //------begin modify by lixiaoxiao 20180315 新旧mac匹配
            deviceInfoEntity = deviceInfoEntityRepo.findByMacAndTrashFalse(mac);
            if (deviceInfoEntity == null) {
                return ApiResponse.prompt(AppCode.DEVICE_NOT_EXIST);
            }
            //------end modify by lixiaoxiao 20180315 新旧mac匹配
        }
        UserDeviceEntity userDeviceEntity = userDeviceEntityRepo.findByUidAndDeviceIdAndTrashFalse(uid, deviceInfoEntity.getDeviceId());
        if (userDeviceEntity == null) {
            return ApiResponse.prompt(AppCode.DEVICE_NOT_YOURS);
        }
        deviceInfoEntity.updateInfo(sn, alias);
        deviceInfoEntity = deviceInfoEntityRepo.save(deviceInfoEntity);
        userDeviceEntity.updateDeviceAlias(alias);
        userDeviceEntityRepo.save(userDeviceEntity);
        if (deviceInfoEntity == null) {
            return ApiResponse.prompt(AppCode.DEVICE_INFO_UPDATE_FAIL);
        }
        return ApiResponse.prompt(AppCode.SC_OK);
    }

    /**
     * 获取设备列表
     *
     * @param skip  跳过n条
     * @param limit 限制n条
     * @return
     */
    public ApiResponse<List<DeviceInfoEntity>> getDeviceList(Integer skip, Integer limit) {
        if (skip == null || limit == null) {
            return ApiResponse.ok(null);
        }
        return ApiResponse.ok(deviceInfoEntityRepo.findDeviceList(skip, limit));
    }

    /**
     * modify by lixiaoxiao 20170810 新增根据mac获取绑定主人的用户名和手机号
     */
    public DeviceFaultVo findByMac(String mac) {
        return userDeviceEntityRepo.findByMac(mac);
    }

    /**
     * 获取设备总数
     *
     * @return
     */
    public ApiResponse<Integer> getDeviceCount() {
        return ApiResponse.ok(deviceInfoEntityRepo.countBySql());
    }

    /**
     * @param deviceId
     * @return
     */
    public ApiResponse<DeviceInfoNewVo> getDeviceNewInfoByDeviceId(String deviceId) {
        DeviceInfoEntity deviceInfo = deviceInfoEntityRepo.findByDeviceIdAndTrashFalse(deviceId);
        DeviceModelInfoEntity deviceModelInfoEntity = deviceModelInfoRepo.findByModelIdAndTrashFalse(deviceInfo.getModelId());
        DeviceInfoNewVo deviceInfoNewVo = deviceInfo.createDeviceInfoNewVo()
                .buidSuitAndUseType(deviceModelInfoEntity.getSuitType(), deviceModelInfoEntity.getUseType());
        return ApiResponse.ok(deviceInfoNewVo);
    }

    /**
     * @param did
     * @return
     */
    public ApiResponse<DeviceInfoNewVo> getDeviceNewInfoByDid(String did) {
        DeviceInfoEntity deviceInfo = deviceInfoEntityRepo.findByDidAndTrashFalse(did);
        DeviceModelInfoEntity deviceModelInfoEntity = deviceModelInfoRepo.findByModelIdAndTrashFalse(deviceInfo.getModelId());
        DeviceInfoNewVo deviceInfoNewVo = deviceInfo.createDeviceInfoNewVo()
                .buidSuitAndUseType(deviceModelInfoEntity.getSuitType(), deviceModelInfoEntity.getUseType());
        return ApiResponse.ok(deviceInfoNewVo);
    }

    /**
     * @param mac
     * @return
     */
    public ApiResponse<DeviceInfoNewVo> getDeviceInfoNewVoByMac(String mac) {
        DeviceInfoEntity deviceInfo = deviceInfoEntityRepo.findByMacAndTrashFalse(mac);
        if (null == deviceInfo) {
            return ApiResponse.prompt(Syscode.DEVICE_NOT_FOUND);
        }
        return ApiResponse.ok(deviceInfo.createDeviceInfoNewVo());
    }

    public ApiResponse<String> getProductKeyByModelItem(String modelItem) {
        String likeItem = "%{\"deviceModel\":\"%" + modelItem + "%";
        List<String> deviceModelInfoEntities = deviceInfoEntityRepo.findByModelItem(likeItem);
        if (deviceModelInfoEntities.size() == 0) {
            return ApiResponse.prompt(BusinessCode.MODEL_ITEM_NOT_FOUND);
        }
        return ApiResponse.ok(deviceModelInfoEntities.get(0));
    }

    /**
     * 去paas做绑定
     * @param deviceInfoWithTokenDto
     * @return
     */
    public ApiResponse getNewOrOldFromPaas(DeviceInfoWithTokenDto deviceInfoWithTokenDto,String newMac){
        DeviceInfoWithTokenDto deviceInfoWithTokenDtoToPaas = new DeviceInfoWithTokenDto();
        BeanUtils.copyAttrs(deviceInfoWithTokenDtoToPaas,deviceInfoWithTokenDto);
        ApiResponse<DeviceMessage> apiResponse = deviceManageService.getDeviceInfo(
                StringUtils.isEmpty(deviceInfoWithTokenDtoToPaas.getProductKey()) ? AppConstant.HOME_WIFI_PRODUCT_KEY : deviceInfoWithTokenDtoToPaas.getProductKey(), newMac);
        if (apiResponse.getCode() != AppCode.SC_OK.getCode()) {
            return apiResponse;
        }
        DeviceMessage deviceMessage = apiResponse.getData();
        deviceInfoWithTokenDtoToPaas.setDid(deviceMessage.getDid());
        deviceInfoWithTokenDtoToPaas.setPassword(deviceMessage.getPasscode());
        ApiResponse passApiResponse = saveToPaas(deviceInfoWithTokenDtoToPaas);
        //失败
        if (passApiResponse.getCode() != AppCode.SC_OK.getCode()) {
            return passApiResponse;
        }else{
            deviceInfoWithTokenDtoToPaas.setMac(newMac);
            return ApiResponse.ok(deviceInfoWithTokenDtoToPaas);
        }
    }

    private String transNewToOld(String newMac){
        StringBuilder stringBuilder = new StringBuilder();
        int begin = 0;
        int end = 2;
        int len = newMac.length()/2;
        for(int i=0; i<len; i++){
            stringBuilder.append(newMac.substring(begin,end)+":");
            begin = begin+2;
            end = end+2;
        }
        return stringBuilder.subSequence(0,stringBuilder.length()-1).toString();
    }

    /**
     * 清除新旧设备并解绑
     * @param appid
     * @param newMac
     * @param oldMac
     */
    private void clearDevice(String appid,String newMac,String oldMac){
        List<DeviceInfoEntity> list = deviceInfoEntityRepo.findDeviceListByMac(newMac, oldMac);
        list.stream().forEach(deviceInfoEntity -> {
            clearDeviceRelation(appid,deviceInfoEntity);
        });
        deviceInfoEntityRepo.deleteDevice(newMac,oldMac);

    }
}
